use std::arch::global_asm;

use proc_macro::TokenStream;
use proc_macro2::Span;
use quote::quote;
use syn::{parse2, Ident, ItemFn};

#[proc_macro]
pub fn proc_macro_mygpio(input: TokenStream) -> TokenStream {
    let s = input.to_string();
    let mut chars = s.chars();
    let pin_group = chars.next().unwrap();
    let pin_number = chars.next().unwrap().to_digit(10).unwrap() as u8;

    let struct_ident = Ident::new(&format!("GPIO_{}", s.to_uppercase()), Span::call_site());
    let pin_group_typename_ident = Ident::new(
        &format!("GPIO{}", pin_group.to_uppercase()),
        Span::call_site(),
    );
    let pin_group_name = Ident::new(
        &format!("gpio{}", pin_group.to_lowercase()),
        Span::call_site(),
    );

    quote! {
        pub struct #struct_ident<'a> {
            #pin_group_name: &'a #pin_group_typename_ident,
        }
        impl<'a> #struct_ident<'a> {
            fn new(#pin_group_name: &'a #pin_group_typename_ident) -> Self {
                #pin_group_name
                    .cfglr
                    .modify(|_, w| w.mode3().variant(0b11).cnf3().variant(0b00));
                #struct_ident { #pin_group_name }
            }
        }

        impl<'a> OutputPin for #struct_ident<'a> {
            #[inline(always)]
            fn set_low(&mut self) -> Result<(), Self::Error> {
                self.#pin_group_name.outdr.modify(|_, w| w.odr3().clear_bit());
                return Ok(());
            }
            #[inline(always)]
            fn set_high(&mut self) -> Result<(), Self::Error> {
                self.#pin_group_name.outdr.modify(|_, w| w.odr3().set_bit());
                return Ok(());
            }
        }

        impl<'a> embedded_hal::digital::ErrorType for #struct_ident<'a> {
            type Error = embedded_hal::digital::ErrorKind;
        }
    }
    .into()
}

#[proc_macro]
pub fn proc_macro_dosome(input: TokenStream) -> TokenStream {
    let i = syn::parse::<Ident>(input).unwrap();
    quote! {
        #i
    }.into()
}

#[proc_macro_attribute]
pub fn interrupt_handler(_attr: TokenStream, item: TokenStream) -> TokenStream {
    let f = parse2::<ItemFn>(item.into()).unwrap();
    let interrupt = _attr.to_string();
    let wrapped_name = f.sig.ident.to_string();
    let start_interrupt = format!(
        r#"
core::arch::global_asm!(
    ".section .text, \"ax\"
    .align 2
    .global {interrupt}
    {interrupt}:
        jal {wrapped_name}
        mret
");"#
    );

    let start_interrupt_asm: proc_macro2::TokenStream = start_interrupt.parse().unwrap();

    println!("{}", start_interrupt);

    quote!(
        #start_interrupt_asm

        #[allow(non_snake_case)]
        #[no_mangle]
        #[link_section = ".trap.rust"]
        #f
    )
    .into()

    // let input: syn::ItemFn = syn::parse(item).unwrap();
    // println!("{:?}", input.sig.output.to_token_stream());
    // // panic!(_attr.to_string());

    // let fn_name = &input.sig.ident;

    // // 生成一个裸函数包装器，插入 mret
    // let expanded = quote! {
    //     // 原函数改为普通实现函数
    //     #[allow(non_snake_case)]
    //     fn #fn_name() {
    //         // 这里可以插入中断入口逻辑（如关闭全局中断）
    //         // 然后调用用户代码
    //         fn_name();
    //     }

    //     // 用户编写的“普通函数”实际被重命名
    //     // #[inline(never)]
    //     // fn inner_#fn_name() #input

    //     // 生成裸函数作为中断入口
    //     #[naked_asm]
    //     #[no_mangle]
    //     #[allow(non_snake_case)]
    //     pub unsafe extern "C" fn #fn_name() {
    //         core::arch::asm!(
    //             // 调用实际的中断处理函数（用户代码）
    //             "call inner_#fn_name",
    //             // 插入 mret
    //             "mret",
    //             // 确保不生成额外代码
    //             options(noreturn)
    //         );
    //     }
    // };

    // expanded.into()
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn it_works() {}
}
